package com.binance.basedao.mybatis;

import org.apache.ibatis.binding.MapperProxy;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Proxy;
import java.lang.reflect.Type;

/**
 * <b>Description:</b>〈解析BaseDao中的方法操作的数据库table切面类〉<br/>
 * @author hongchaoMao <br/>
 *         Create date: 2017/9/23
 * @version v1.0.0
 */
@Aspect
public class ParseTableNameAspect
{
    private static final String BASE_DAO_CNAME = BaseMapper.class.getClass().getName();
    private static final String MODEL_SUFIX = "Model";

    @Around("execution(* com.binance.basedao.mybatis.BaseMapper.*(..))")
    public Object invoke(ProceedingJoinPoint proceedingJoinPoint) throws Throwable
    {
        parseTableName(proceedingJoinPoint);
        Object o = proceedingJoinPoint.proceed();
        BaseProvider.threadLocalRemove();
        return o;
    }
    
    private void parseTableName(ProceedingJoinPoint proceedingJoinPoint) throws NoSuchFieldException,
            IllegalAccessException, ClassNotFoundException
    {
        // 将modelClass添加到线程变量
        if (proceedingJoinPoint.getArgs() != null && proceedingJoinPoint.getArgs().length > 0) {
            Class clazz = proceedingJoinPoint.getArgs()[0].getClass();
            if (clazz.getName().endsWith(MODEL_SUFIX)) {
                BaseProvider.setModelClass(clazz);
            }else {
                setModelClassFromProxy(proceedingJoinPoint);
            }
        }
        else {
            setModelClassFromProxy(proceedingJoinPoint);
        }
    }

    private void setModelClassFromProxy(ProceedingJoinPoint proceedingJoinPoint) throws NoSuchFieldException, IllegalAccessException, ClassNotFoundException {
        // 获取代理目标对象
        Field h = Proxy.class.getDeclaredField("h");
        h.setAccessible(true);
        Object proxyTarget = h.get(proceedingJoinPoint.getTarget());
        // 获取dao类
        Field mapperInterface = MapperProxy.class.getDeclaredField("mapperInterface");
        mapperInterface.setAccessible(true);
        Class<?> cl = (Class<?>) mapperInterface.get(proxyTarget);
        String modelName = null;
        // 因为是接口可能有多个
        Type[] types = cl.getGenericInterfaces();
        for (Type t : types) {
            // 只针对接口类型必须是BaseDao的
            ParameterizedType parameterizedType = (ParameterizedType) t;
            String parentIntfName = parameterizedType.getRawType().getClass().getName();
            if (BASE_DAO_CNAME.equals(parentIntfName)) {
                // 获取泛型类型
                Type[] temp = parameterizedType.getActualTypeArguments();
                for (Type c : temp) {
                    modelName = ((Class) c).getName();
                }
                break;
            }
        }
        // 获取model类
        BaseProvider.setModelClass(Class.forName(modelName));
    }
}

